package com.quanyan.club.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.quanyan.api.APIResponse;
import com.quanyan.api.enums.ApiResponseEnum;
import com.quanyan.api.enums.AssetsType;
import com.quanyan.assets.request.ReqRuleDetail;
import com.quanyan.assets.response.RespRuleDetail;
import com.quanyan.assets.service.UserAssetsService;
import com.quanyan.club.entity.db.TbAASettlementRefundDetail;
import com.quanyan.club.entity.db.TbAASettlementRefundDetailExample;
import com.quanyan.club.entity.db.TbClubOfflineAccount;
import com.quanyan.club.entity.db.TbClubOfflineAccountExample;
import com.quanyan.club.entity.db.TbClubOfflineAccountStream;
import com.quanyan.club.entity.db.TbClubOnlineAccount;
import com.quanyan.club.entity.db.TbClubOnlineAccountExample;
import com.quanyan.club.entity.db.TbClubOnlineAccountStream;
import com.quanyan.club.entity.db.TbClubOnlineMemberAccount;
import com.quanyan.club.entity.db.TbClubOnlineMemberAccountExample;
import com.quanyan.club.entity.db.TbClubOnlineMemberAccountStream;
import com.quanyan.club.entity.db.TbClubOnlineMemberAccountStreamExample;
import com.quanyan.club.entity.vo.resp.ClubMemberAccountStreamInfo;
import com.quanyan.club.mapper.ClubActivityMapper;
import com.quanyan.club.mapper.TbAASettlementRefundDetailMapper;
import com.quanyan.club.mapper.TbClubOfflineAccountMapper;
import com.quanyan.club.mapper.TbClubOfflineAccountStreamMapper;
import com.quanyan.club.mapper.TbClubOnlineAccountMapper;
import com.quanyan.club.mapper.TbClubOnlineAccountStreamMapper;
import com.quanyan.club.mapper.TbClubOnlineMemberAccountMapper;
import com.quanyan.club.mapper.TbClubOnlineMemberAccountStreamMapper;
import com.quanyan.club.service.ClubAccountService;
import com.quanyan.club.util.NumberGenerator;
import com.quanyan.common.constants.Constants;
import com.quanyan.common.utils.CommonUtils;
import com.quanyan.orderpay.request.ReqSysPayInfo;
import com.quanyan.orderpay.response.RespPayInfo;
import com.quanyan.orderpay.service.OrderPayService;

import com.quanyan.user.response.RespUserInfoBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author Hugo.Wwg
 * @Since 2016-07-06
 */
@Service
public class ClubAccountServiceImpl extends BaseServiceImpl implements ClubAccountService {

    @Autowired
    private TbClubOnlineAccountMapper tbClubOnlineAccountMapper;
    @Autowired
    private TbClubOnlineAccountStreamMapper tbClubOnlineAccountStreamMapper;
    @Autowired
    private TbClubOfflineAccountMapper tbClubOfflineAccountMapper;
    @Autowired
    private TbClubOfflineAccountStreamMapper tbClubOfflineAccountStreamMapper;
    @Autowired
    private TbClubOnlineMemberAccountMapper clubOnlineMemberAccountMapper;
    @Autowired
    private ClubActivityMapper clubActivityMapper;
    @Autowired
    private OrderPayService orderPayService;
    @Autowired
    private UserAssetsService userAssetsService;
    @Autowired
    private TbClubOnlineMemberAccountStreamMapper clubOnlineMemberAccountStreamMapper;
    @Autowired
    private TbAASettlementRefundDetailMapper tbAASettlementRefundDetailMapper;
    private Logger logger = LoggerFactory.getLogger(ClubAccountServiceImpl.class);

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public APIResponse updateClubOnlineAccountBalance(Integer clubId, Integer activityId, String serialNo, String tradeNo,
                                                      BigDecimal fee, String remark, boolean incr, int type) {

        if (clubId <= 0 || fee == null || fee.doubleValue() <= 0) {
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_CANT_BE_EMPTY);
        }

        TbClubOnlineAccountExample tbClubOnlineAccountExample = new TbClubOnlineAccountExample();
        tbClubOnlineAccountExample.createCriteria().
                andClubIdEqualTo(clubId).andIsDeleteEqualTo((byte) 0);

        List<TbClubOnlineAccount> tbClubOnlineAccounts =
                tbClubOnlineAccountMapper.selectByExample(tbClubOnlineAccountExample);
        if (CollectionUtils.isEmpty(tbClubOnlineAccounts)) {
            return APIResponse.returnFail("俱乐部账户不存在");
        }

        TbClubOnlineAccount tbClubOnlineAccount = tbClubOnlineAccounts.get(0);

        Map<String, Object> paraMap = Maps.newHashMap();
        paraMap.put("fee", fee);
        paraMap.put("id", tbClubOnlineAccount.getId());
        int ret = 0;
        if (incr) {
            ret = clubActivityMapper.incrementOnlineClubAccount(paraMap);
            if (ret != 1) {
                return APIResponse.returnFail("充值失败");
            }
        } else {
            ret = clubActivityMapper.reduceOnlineClubAccount(paraMap);
            if (ret != 1) {
                return APIResponse.returnFail("账户余额不足");
            }
        }

        //记流水
        TbClubOnlineAccountStream tbClubOnlineAccountStream = new TbClubOnlineAccountStream();
        tbClubOnlineAccountStream.setActivityId(activityId);
        tbClubOnlineAccountStream.setClubId(clubId);
        tbClubOnlineAccountStream.setOutTradeNo(tradeNo);
        tbClubOnlineAccountStream.setSerialNo(serialNo);
        tbClubOnlineAccountStream.setClubOnlineAccountId(tbClubOnlineAccount.getId());
        tbClubOnlineAccountStream.setCreateTime(new Date());
        tbClubOnlineAccountStream.setPreAmount(tbClubOnlineAccount.getMoneyUsable());
        tbClubOnlineAccountStream.setType((byte) type);
        if (incr) {
             //收入
            tbClubOnlineAccountStream.setIncomeOnline(fee);
            tbClubOnlineAccountStream.setSufAmount(tbClubOnlineAccount.getMoneyTotal().add(fee));
        } else {
            //支出
            tbClubOnlineAccountStream.setOutputOnline(fee);
            tbClubOnlineAccountStream.setSufAmount(tbClubOnlineAccount.getMoneyTotal().subtract(fee));
        }
        tbClubOnlineAccountStream.setStatus((byte) 1);
        tbClubOnlineAccountStream.setRemark(remark);
        tbClubOnlineAccountStream.setCreateTime(new Date());
        if (type == 1){
            logger.warn("----------结算 club online account 记录流水：" + JSON.toJSONString(tbClubOnlineAccountStream));
        }
        int count = tbClubOnlineAccountStreamMapper.insertSelective(tbClubOnlineAccountStream);
        if (count <= 0) {
            return APIResponse.returnFail("线上账户流水记录失败");
        }
        return APIResponse.returnSuccess();
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public APIResponse incrementOfflineClubAccount(Integer clubId, Integer activityId,
                                                   BigDecimal fee, String remark) {

        if (clubId <= 0 || activityId <= 0 || fee == null || fee.doubleValue() <= 0) {
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_CANT_BE_EMPTY);
        }

        TbClubOfflineAccountExample tbClubOfflineAccountExample = new TbClubOfflineAccountExample();
        tbClubOfflineAccountExample.createCriteria().
                andClubIdEqualTo(clubId).andIsDeleteEqualTo((byte) 0);

        List<TbClubOfflineAccount> tbClubOfflineAccounts =
                tbClubOfflineAccountMapper.selectByExample(tbClubOfflineAccountExample);
        if (CollectionUtils.isEmpty(tbClubOfflineAccounts)) {
            return APIResponse.returnFail("俱乐部线下账户不存在");
        }

        TbClubOfflineAccount tbClubOfflineAccount = tbClubOfflineAccounts.get(0);

        Map<String, Object> paraMap = Maps.newHashMap();
        paraMap.put("fee", fee);
        paraMap.put("id", tbClubOfflineAccount.getId());
        clubActivityMapper.incrementOfflineClubAccount(paraMap);

        TbClubOfflineAccountStream tbClubOfflineAccountStream = new TbClubOfflineAccountStream();
        tbClubOfflineAccountStream.setActivityId(activityId);
        tbClubOfflineAccountStream.setClubId(clubId);
        tbClubOfflineAccountStream.setClubOfflineAccountId(tbClubOfflineAccount.getId());
        tbClubOfflineAccountStream.setCreateTime(new Date());
        tbClubOfflineAccountStream.setIncomeOffline(fee);
        tbClubOfflineAccountStream.setType((byte) 0);
        tbClubOfflineAccountStream.setRemark(remark);
        tbClubOfflineAccountStream.setPreAmount(tbClubOfflineAccount.getMoneyTotal());
        tbClubOfflineAccountStream.setSufAmount(tbClubOfflineAccount.getMoneyTotal().add(fee));
        int ret = tbClubOfflineAccountStreamMapper.insertSelective(tbClubOfflineAccountStream);
        if (ret != 1) {
            return APIResponse.returnFail("增加俱乐部线下账户金额失败");
        }

        return APIResponse.returnSuccess();
    }

    public TbClubOnlineMemberAccount queryClubMemberAccount(Integer clubId, Integer userId) {
        if (clubId == null || userId == null) {
            return null;
        }
        TbClubOnlineMemberAccountExample example = new TbClubOnlineMemberAccountExample();
        example.createCriteria().andClubIdEqualTo(clubId).
                andUidEqualTo(userId).andIsDeleteEqualTo((byte) 0);
        List<TbClubOnlineMemberAccount> accounts =
                clubOnlineMemberAccountMapper.selectByExample(example);

        if (CollectionUtils.isEmpty(accounts)) {
            return null;
        }
        return accounts.get(0);
    }

    /**
     * 增加或扣除俱乐部成员账户余额
     *
     * @param balanceAmount 抵扣金额
     * @param isAdd         是否添加 true为增加 false为扣除
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ClubMemberAccountStreamInfo addOrDeductionPersonClubAccountBalance(
            BigDecimal balanceAmount, Integer userId,
            Integer clubId, boolean isAdd) {
        if (balanceAmount == null || balanceAmount.doubleValue() <= 0
                || userId == null || userId <= 0 || clubId == null || clubId <= 0) {
            return null;
        }

        TbClubOnlineMemberAccount memberAccountInfo = queryClubMemberAccount(clubId, userId);
        if (memberAccountInfo == null) {
            return null;
        }

        Map<String, Object> paraMap = Maps.newHashMap();
        paraMap.put("balanceAmount", balanceAmount);
        paraMap.put("uid", userId);
        paraMap.put("clubId", clubId);

        int deductionCount = 0;
        if (isAdd) {
            deductionCount = clubActivityMapper.addPersonClubAccountBalance(paraMap);
        } else {
            deductionCount = clubActivityMapper.deductionPersonClubAccountBalance(paraMap);
        }

        if (deductionCount == 0) {
            return null;
        }

        ClubMemberAccountStreamInfo memberAccountStreamInfo = new ClubMemberAccountStreamInfo();
        memberAccountStreamInfo.setUserId(userId);
        memberAccountStreamInfo.setClubId(clubId);
        memberAccountStreamInfo.setClubOnlineMemberAccountId(memberAccountInfo.getId());
        memberAccountStreamInfo.setPreAmount(memberAccountInfo.getMoneyTotal());

        if (isAdd) {
            //增加金额
            memberAccountStreamInfo.setIncome(balanceAmount);
            memberAccountStreamInfo.setSufAmount(
                    memberAccountInfo.getMoneyTotal().add(balanceAmount));
        } else {
            //扣除金额
            memberAccountStreamInfo.setOutput(balanceAmount);
            memberAccountStreamInfo.setSufAmount(
                    memberAccountInfo.getMoneyTotal().subtract(balanceAmount));
        }

        return memberAccountStreamInfo;
    }

    /**
     * 获取个人鸟蛋
     */
    public RespRuleDetail getPersonEggsInfo(Integer currentUserId, BigDecimal dealAmount) {
        //获取个人鸟蛋
        com.quanyan.api.APIRequest<ReqRuleDetail> apiRequest = new com.quanyan.api.APIRequest();
        ReqRuleDetail reqRuleDetail = new ReqRuleDetail();
        reqRuleDetail.setUid(currentUserId);
        reqRuleDetail.setAssetsType(AssetsType.ASSETS_EGGS.getId().byteValue());
        reqRuleDetail.setSystemCode(Constants.CLUB_SYSTEM_CODE);
        reqRuleDetail.setBusinessCode(Constants.CLUB_ACTIVITY_ORDER_BUSINESS_CODE);
        reqRuleDetail.setOrderAmount(dealAmount);//总金额
        apiRequest.setData(reqRuleDetail);
        APIResponse<List<RespRuleDetail>> apiResponse =
                userAssetsService.getUserAccumulateAndRule(apiRequest);

        if (!apiResponse.isRet()) {
            return null;
        }

        List<RespRuleDetail> tbUserAssetsList = apiResponse.getData();
        if (CollectionUtils.isEmpty(tbUserAssetsList)) {
            return null;
        }

        return apiResponse.getData().get(0);
    }

    /**
     * 获取可用支付方式
     */
    public List<RespPayInfo> getSysPayInfo(String sourceBusinessId) {
        ReqSysPayInfo reqSysPayInfo = new ReqSysPayInfo();
        reqSysPayInfo.setSourceSystemId(Constants.CLUB_SYSTEM_CODE);
        reqSysPayInfo.setSourceBusinessId(sourceBusinessId);
        APIResponse<List<RespPayInfo>> respPayInfoResponse =
                orderPayService.selectEnablePayInfos(reqSysPayInfo);

        if (!respPayInfoResponse.isRet()) {
            return null;
        }

        List<RespPayInfo> respPayInfo = respPayInfoResponse.getData();
        if (CollectionUtils.isEmpty(respPayInfo)) {
            return null;
        }
        return respPayInfo;
    }

    /**
     * 记录俱乐部成员线上账户金额变动流水
     */
    public void recordPersonClubAccountDeductibleStream(Integer uid,
                                                        Integer activityId,
                                                        String remark,
                                                        byte payId, //支付方式
                                                        Integer clubId,
                                                        ClubMemberAccountStreamInfo streamInfo,
                                                        String orderSystemOrderNo,
                                                        byte type, byte status) {
        TbClubOnlineMemberAccountStream memberAccountStream = new TbClubOnlineMemberAccountStream();
        memberAccountStream.setUid(uid);
        memberAccountStream.setProductId(activityId);
        memberAccountStream.setClubOnlineMemberAccountId(
                streamInfo.getClubOnlineMemberAccountId());
        String orderNo = CommonUtils.generateBusinessOrderNo(Constants.CLUB_SYSTEM, uid);
        memberAccountStream.setSerialNo(orderNo);//唯一编号
        memberAccountStream.setClubId(clubId);
        memberAccountStream.setPreAmount(streamInfo.getPreAmount());
        memberAccountStream.setSource("online");

        String payMode = "";
        if (payId == 1) {
            payMode = "支付宝充值";
        }
        if (payId == 2) {
            payMode = "微信充值";
        }
        String userName = uid.toString();
        RespUserInfoBase userInfo = getUserInfoBase(uid);
        if (userInfo != null){
            userName = userInfo.getNickName();
        }

        switch (type) {
            case 0: //充值
                memberAccountStream.setIncome(streamInfo.getIncome());
                memberAccountStream.setCheques("百灵鸟"); // 收款方
                memberAccountStream.setDrawee(userName); //付款方
                memberAccountStream.setTypeIntro("在线充值");
                memberAccountStream.setPayMode(payMode);
                memberAccountStream.setRemark(remark);
                break;
            case 1: //消费
                memberAccountStream.setOutput(streamInfo.getOutput());
                memberAccountStream.setCheques("百灵鸟");
                memberAccountStream.setDrawee(userName);
                memberAccountStream.setTypeIntro("订单付款");
                memberAccountStream.setPayMode("抵扣订单费用");
                memberAccountStream.setRemark(remark);
                break;
            case 2: //退款
                memberAccountStream.setIncome(streamInfo.getIncome());
                memberAccountStream.setCheques(userName);
                memberAccountStream.setDrawee("百灵鸟");
                memberAccountStream.setTypeIntro("订单退款");
                memberAccountStream.setPayMode("原路返还");
                memberAccountStream.setRemark(remark);
                break;
        }

        memberAccountStream.setType(type);
        memberAccountStream.setSufAmount(streamInfo.getSufAmount());
        memberAccountStream.setCreateTime(new Date());
        memberAccountStream.setOutTradeNo(orderSystemOrderNo);
        memberAccountStream.setPayChannel(payId);
        memberAccountStream.setStatus(status);
        clubOnlineMemberAccountStreamMapper.insertSelective(memberAccountStream);
    }

    @Override
    public TbClubOnlineMemberAccountStream getPersonClubAccountStream(Integer uid, Integer clubId,
                                                                      Integer activityId,
                                                                      Integer type) {

        if (uid == null || uid < 0
                || clubId == null || clubId < 0
                || activityId == null || activityId < 0
                || type == null || type < 0) {
            return null;
        }

        TbClubOnlineMemberAccountStreamExample example
                = new TbClubOnlineMemberAccountStreamExample();
        example.createCriteria().andUidEqualTo(uid).andClubIdEqualTo(clubId)
                .andProductIdEqualTo(activityId).andTypeEqualTo(type.byteValue()).
                andStatusEqualTo((byte) 2);
        example.setOrderByClause(" create_time desc");
        List<TbClubOnlineMemberAccountStream> tbClubOnlineMemberAccountStreams =
                clubOnlineMemberAccountStreamMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(tbClubOnlineMemberAccountStreams)) {
            return null;
        }
        return tbClubOnlineMemberAccountStreams.get(0);
    }

    @Override
    public boolean updatePersonClubAccountStream(TbClubOnlineMemberAccountStream accountStream) {
        if (accountStream == null) {
            return false;
        }
        int count = clubOnlineMemberAccountStreamMapper.updateByPrimaryKeySelective(accountStream);
        if (count <= 0) {
            return false;
        }
        return true;
    }

    @Override
    public boolean deletePersonClubAccountStream(Integer accountStreamId) {
        if (accountStreamId == null) {
            return false;
        }
        int count = clubOnlineMemberAccountStreamMapper.deleteByPrimaryKey(accountStreamId);
        if (count <= 0) {
            return false;
        }
        return true;
    }

    @Override
    public boolean recordAASettlementRefundDetail(TbAASettlementRefundDetail refundDetail) {
        if (refundDetail == null) return false;
        int count = tbAASettlementRefundDetailMapper.insertSelective(refundDetail);
        if (count <= 0) {
            return false;
        }
        return true;
    }

    @Override
    public TbAASettlementRefundDetail getTbAASettlementRefundDetail(
            String orderNo, Integer activityId) {
        TbAASettlementRefundDetailExample refundDetailExample =
                new TbAASettlementRefundDetailExample();
        refundDetailExample.createCriteria()
                .andOrderNoEqualTo(orderNo).andActivityIdEqualTo(activityId);

        List<TbAASettlementRefundDetail> settlementRefundDetails
                = tbAASettlementRefundDetailMapper.selectByExample(refundDetailExample);
        if (CollectionUtils.isEmpty(settlementRefundDetails)) {
            return null;
        }

        return settlementRefundDetails.get(0);
    }

    @Override
    public TbAASettlementRefundDetail getTbAASettlementRefundDetail(
            String orderNo, Integer activityId, Integer orderUid) {
        TbAASettlementRefundDetailExample refundDetailExample =
                new TbAASettlementRefundDetailExample();
        refundDetailExample.createCriteria()
                .andOrderNoEqualTo(orderNo)
                .andOrderUidEqualTo(orderUid)
                .andActivityIdEqualTo(activityId);

        List<TbAASettlementRefundDetail> settlementRefundDetails
                = tbAASettlementRefundDetailMapper.selectByExample(refundDetailExample);
        if (CollectionUtils.isEmpty(settlementRefundDetails)) {
            return null;
        }

        return settlementRefundDetails.get(0);
    }

    @Override
    public boolean updateTbAASettlementRefundDetailStatus(
            TbAASettlementRefundDetail refundDetail) {
        if (refundDetail == null) {
            return false;
        }
        int count = tbAASettlementRefundDetailMapper.updateByPrimaryKeySelective(refundDetail);
        if (count <= 0) {
            return false;
        }
        return true;
    }
}